//Copy from hikari
#ifndef _FLASH_CALL_H_
#define _FLASH_CALL_H_

#include "SwfUI.h"

namespace SwfUI
{
	namespace detail
	{
		inline void replaceAll(std::wstring &sourceStr, const std::wstring &replaceWhat, const std::wstring &replaceWith)
		{
			for(size_t i = sourceStr.find(replaceWhat); i != std::wstring::npos; i = sourceStr.find(replaceWhat, i + replaceWith.length()))
			{
				sourceStr.erase(i, replaceWhat.length());
				sourceStr.insert(i, replaceWith);
			}
		}

		std::wstring serializeValue(const Argument& value)
		{
			switch(value.getType())
			{
			case AT_NULL:
				return L"<null/>";
			case AT_BOOLEAN:
				return ((bool)value)? L"<true/>" : L"<false/>";
			case AT_NUMERIC:
				{
					return L"<number>" + (const std::wstring&)value + L"</number>";
				}
			case AT_STRING:
				{
					std::wstring stringVal = (const std::wstring&)value;
					replaceAll(stringVal, L"&", L"&amp;");
					replaceAll(stringVal, L"\"", L"&quot;");
					replaceAll(stringVal, L"'", L"&apos;");
					replaceAll(stringVal, L"<", L"&lt;");
					replaceAll(stringVal, L">", L"&gt;");

					return L"<string>" + stringVal + L"</string>";
				}
			}

			return L"<null/>";
		}

		Argument deserializeValue(const std::wstring& valueStr)
		{
			if(valueStr == L"<null/>")
				return Argument::Null;
			else if(valueStr == L"<true/>")
				return true;
			else if(valueStr == L"<false/>")
				return false;

			if(valueStr.substr(0, 8) == L"<string>")
			{
				std::wstring stringVal = valueStr.substr(8, valueStr.find(L"</string>", 8) - 8);
				replaceAll(stringVal, L"&quot;", L"\"");
				replaceAll(stringVal, L"&apos;", L"'");
				replaceAll(stringVal, L"&lt;", L"<");
				replaceAll(stringVal, L"&gt;", L">");
				replaceAll(stringVal, L"&amp;", L"&");
				return stringVal;
			}
			else if(valueStr.substr(0, 8) == L"<number>")
			{
				static std::wstringstream converter;
				converter.clear();
				float numValue = 0.0f;

				converter.str(valueStr.substr(8, valueStr.find(L"</number>", 8) - 8));
				converter >> numValue;

				return numValue;
			}

			return Argument::Null;
		}

		void serializeInvocation(const std::wstring& funcName, const ArgumentList& args, std::wstring& result)
		{
			result += L"<invoke name=\"" + funcName + L"\" returntype=\"xml\">";

			if(args.size())
			{
				result += L"<arguments>";
				for(ArgumentList::const_iterator i = args.begin(); i != args.end(); i++)
					result += serializeValue(*i);
				result += L"</arguments>";
			}

			result += L"</invoke>";
		}

		bool deserializeInvocation(const std::wstring& xmlString, std::wstring& funcName, ArgumentList& args)
		{
			size_t indexA = 0;
			size_t indexB = 0;

			if((indexA = xmlString.find(L"<invoke name=\"")) == std::wstring::npos)
				return false;

			if((indexB = xmlString.find(L"\"", indexA + 14)) == std::wstring::npos)
				return false;

			funcName = xmlString.substr(indexA + 14, indexB - (indexA + 14));
			args.clear();

			if((indexA = xmlString.find(L"<arguments>", indexB)) == std::wstring::npos)
				return true;

			indexA += 11;
			std::wstring argString(xmlString.substr(indexA, xmlString.find(L"</arguments>", indexA) - indexA));

			for(indexA = 0, indexB = 0; true;)
			{
				if((indexA = argString.find(L"<", indexB)) == std::wstring::npos)
					break;

				if((indexB = argString.find(L">", indexA)) == std::wstring::npos)
					break;

				if(argString[indexB-1] != L'/')
				{
					if((indexB = argString.find(L">", indexB + 1)) == std::wstring::npos)
						break;
				}

				args.push_back(deserializeValue(argString.substr(indexA, indexB + 1 - indexA)));
			}

			return true;
		}
	}
}

#endif